package jwt

import (
	"context"
	"errors"
	"fmt"
	"github.com/golang-jwt/jwt/v5"
	"strings"
	"time"
)

// JWTHandler JWT 服务处理
type JWTHandler struct {
	claims *JWTClaimsItem
	ctx    context.Context
	HookHandler
}

// New 实例JWT
func New(claims ClaimsItem) *JWTHandler {
	// 注册JWT要求
	return &JWTHandler{
		claims: registerClaimsItem(claims),
	}
}

// Ctx 设置上下文
func (j *JWTHandler) Ctx(ctx context.Context) *JWTHandler {
	j.ctx = ctx
	return j
}

// 创建JWT Token
func (j *JWTHandler) CreateToken(detail AccountDetail) (tokenItem *TokenItem, err error) {
	// 实例token
	t := jwt.NewWithClaims(j.claims.SignMethod, RegisteredClaimsItem{
		AccountDetail:    detail,
		RegisteredClaims: j.claims.Claims,
	})

	// 初始化
	tokenItem = &TokenItem{}

	// 通过密钥进行加密并获取Token
	tokenItem.Token, err = t.SignedString([]byte(j.claims.Secret))
	if err != nil {
		return nil, fmt.Errorf(`Create JWT token value failed %w`, err)
	}

	// 获取Token效期
	expire, err := t.Claims.GetExpirationTime()
	if err != nil {
		return nil, fmt.Errorf(`Create JWT token expire failed %w, TokenValue：%s`, err, tokenItem.Token)
	}
	// 格式化效期时间
	tokenItem.Expire = expire.Format(time.DateTime)

	// 缓存token信息
	if j.HookHandler.Create != nil {
		err = j.HookHandler.Create(j.ctx, AuthTokenItem{
			TokenItem:    *tokenItem,
			RefreshCount: detail.RefreshCount, // 已刷新次数：0新创建Token，大于0新刷的token
		})
	}
	return
}

// ParseToken 解析Token
func (j *JWTHandler) ParseToken(token string) (claims *RegisteredClaimsItem, err error) {
	token = j.FilterPrefix(token)
	if j.HookHandler.Verify != nil {
		// 验证Token已过期
		if err = j.HookHandler.Verify(j.ctx, token); err != nil {
			return nil, err
		}
	}
	// 解析Token
	t, err := jwt.ParseWithClaims(token, &RegisteredClaimsItem{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(j.claims.Secret), nil
	})
	if err != nil {
		return nil, fmt.Errorf(`Parse JWT token failed %w`, err)
	}

	// Token失效
	if !t.Valid {
		return nil, errors.New("The JWT token is invalid or expired")
	}

	// 断言并解析用户信息
	claims, ok := t.Claims.(*RegisteredClaimsItem)
	if !ok {
		return nil, errors.New(`Failed to assert token claims Or token expired`)
	}
	return claims, nil
}

// RefreshToken 根据旧的Token创建新的Token
func (j *JWTHandler) RefreshToken(refreshToken string) (tokenItem *TokenItem, err error) {
	// 解析并验证token是否过期
	claims, err := j.ParseToken(refreshToken)
	if err != nil {
		return nil, err
	}

	// 获取授权Token
	item, err := j.ReadHook(refreshToken)
	if err != nil {
		return nil, err
	}

	// 验证token内容是否存在
	if item != nil {
		// token刷新次数已达最大次数
		if item.RefreshCount >= j.claims.MaxRefreshCount {
			return nil, errors.New(`The token refresh count has reached the maximum number of times`)
		}
		// 设置新的Token刷新次数
		claims.RefreshCount += 1
	}

	// 创建新token
	tokenItem, err = j.CreateToken(claims.AccountDetail)
	if err == nil {
		// 刷新成功，移除掉旧Token
		err = j.RemoveHook(refreshToken)
	}
	return
}

// FilterPrefix 过滤Token前缀和右边空格
func (j *JWTHandler) FilterPrefix(token string) string {
	return strings.TrimSpace(strings.TrimPrefix(token, j.claims.TokenHeadName))
}

// FillPrefixToken Token返回填充前缀后token
func (j *JWTHandler) FillPrefixToken(token string) string {
	return fmt.Sprintf(`%s %s`, j.claims.TokenHeadName, token)
}
